package com.cgs.query.remote.netty

import com.cgs.query.handler.RemoteHandler
import com.cgs.query.service.IQueryDefineService
import com.cgs.query.service.IQueryService
import com.cgs.query.util.Utils
import com.sucsoft.kotlin.annotation.AllOpen
import mu.KotlinLogging
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.context.ApplicationListener
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Import
import org.springframework.context.event.ContextRefreshedEvent
import java.net.InetSocketAddress
import java.util.*
import java.util.concurrent.atomic.AtomicBoolean


private val logger = KotlinLogging.logger { }

@AllOpen
@Configuration
@Import(NettyClientConfiguration::class, NettyServiceConfiguration::class)
open class NettyConfiguration {
    @Bean
    @ConditionalOnMissingBean
    open fun protostuffSerializer(): Serialization = ProtostuffSerializer()

}

@Configuration
@ConditionalOnMissingBean(IQueryDefineService::class)
@ConditionalOnProperty(name = ["sql.runner.remote.type"], havingValue = "netty")
open class NettyClientConfiguration {

    @Value("\${sql.runner.app.name:unknown}")
    private lateinit var appName: String
    @Value("\${sql.runner.remote.urls:}")
    private lateinit var urls: Array<String>
    @Value("\${sql.runner.remote.netty.timeout:2}")
    private var timeout: Long = 2L

    @Bean
    open fun nettyRemoteHandler(serialization: Serialization): RemoteHandler =
            NettyRemoteHandler(urls, serialization, timeout).apply {
                logger.info { "开启Netty传输:${Arrays.toString(urls)}" }
                hello(appName)
            }
}

@Configuration
@ConditionalOnBean(IQueryDefineService::class)
open class NettyServiceConfiguration : ApplicationListener<ContextRefreshedEvent> {

    @Value("\${sql.runner.remote.netty.port:9999}")
    private lateinit var ports: Array<String>
    @Autowired
    private lateinit var queryService: IQueryService
    @Autowired
    private lateinit var serialization: Serialization

    @Value("\${sql.runner.remote.netty.timeout:2}")
    private var timeout: Long = 2L

    @Bean
    open fun nettyRemoteHandler(serialization: Serialization): RemoteHandler =
            NettyRemoteHandler(arrayOf(), serialization, timeout).apply {
                logger.info { "开启Netty连接器" }
            }

    @Bean
    @ConditionalOnMissingBean(INettyServerManager::class)
    open fun simpleNettyServerManager(): INettyServerManager = SimpleNettyServerManager()

    override fun onApplicationEvent(event: ContextRefreshedEvent?) {
        val applicationContext = event!!.applicationContext
        Utils.nullAndThen(applicationContext.parent) {
            val nettyServerManager = applicationContext.getBean(INettyServerManager::class.java)
            ports.forEach { port ->
                NettyServer(queryService, InetSocketAddress(port.toInt()), serialization).apply {
                    start()
                    nettyServerManager.registryNettyServer(port, this)
                }
            }
        }
    }
}